package com.smartcommunity.service.dataImport;

import cn.hutool.core.util.StrUtil;
import com.smartcommunity.base.bean.ExceptionCode;
import com.smartcommunity.base.common.CacheMap;
import com.smartcommunity.base.common.DataImport;
import com.smartcommunity.bean.constant.Constant;
import com.smartcommunity.bean.entity.ImportErrorMsg;
import com.smartcommunity.bean.entity.ImportField;
import com.smartcommunity.bean.model.Result;
import com.smartcommunity.controller.DataImportBase;
import com.smartcommunity.entity.building.BuildingAddReq;
import com.smartcommunity.entity.building.BuildingEditReq;
import com.smartcommunity.entity.building.BuildingEntity;
import com.smartcommunity.entity.building.BuildingExitsReq;
import com.smartcommunity.entity.building.UnitAddReq;
import com.smartcommunity.exception.BusinessException;
import com.smartcommunity.log.interceptor.Log;
import com.smartcommunity.service.building.BuildingService;
import com.smartcommunity.service.dataImport.model.BuildExportModel;
import com.smartcommunity.utils.RegExUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.map.HashedMap;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.stream.Collectors;

import static org.apache.commons.lang3.StringUtils.EMPTY;
import static org.apache.commons.lang3.StringUtils.length;

/**
 * 楼栋模板导入
 */
@Component("build")
@Slf4j
public class BuildImport extends DataImportBase implements DataImport {

    @Autowired
    private BuildingService buildingService;

    /**
     * 模板类型
     */
    private String type = "楼栋";

    /**
     * 内容标题
     */
    private String[] headerTitle = new String[]{"小区编号","楼栋编号", "单元号", "起始楼层号","结束楼层号", "起始房号","每层户数"};

    /**
     * 错误信息
     */
    private String[] headerErrorMsg = new String[]{
            "为空、或此小区编号不存在、或长度超过64位",
            "为空、或长度超过64位",
            "为空、或长度超过10位",
            "为空、或数值超过1-150范围、或不是数字",
            "为空、或数值超过1-150范围、或不是数字",
            "为空、或数值超过1-100范围、或不是数字",
            "为空、或数值超过1-100范围、或不是数字"};

    /**
     * key taskId,value progress
     */
    final int cacheSize = 100000;
    Map<String, Integer> progressTag = new LinkedHashMap<String, Integer>((int) Math.ceil(cacheSize / 0.75f) + 1, 0.75f, true) {
        @Override
        protected boolean removeEldestEntry(Map.Entry<String, Integer> eldest) {
            return size() > cacheSize;
        }
    };

    @Override
    @Log(info = "楼栋模板导入")
    public String importData(List list, String villageCode, String fileName, String taskId, HttpServletResponse response) throws IllegalArgumentException, BusinessException {
        progressTag.put(taskId, 10);
        ImportErrorMsg msg = getFiledInfo(type, headerTitle, headerErrorMsg);
        List<ImportField> fieldList = msg.getFieldList();
//        if (StringUtils.isBlank(villageCode)) {
//            throw new BusinessException("小区编号为空！");
//        }
        List<BuildingAddReq> buildList = new ArrayList<>();
        Map<String, BuildingAddReq> buildMap = new HashMap<>();
        Map<String, UnitAddReq> unitAddReqMap = new HashedMap();
        List<Object[]> objList = (List<Object[]>) list;
        //存储错误信息
        List<BuildExportModel> dataListCopy = new ArrayList<>();
        BuildingAddReq building;
        UnitAddReq unit;
        boolean isNewBuilding = false;
        int errorCount = 0;
        int size = objList.size();
        for (int i = 0; i < size; i++) {
            boolean isError = false;
            int currentRow = Constant.START_ROW + i;
            Object[] objects = objList.get(i);

            // 列长度校验，防止导入文件的列被删除
            int fixColumnLen = 7;
            if (objects.length < fixColumnLen) {
                throw new BusinessException("模板文件列数不对，请检查模板文件！");
            }

            // 空行校验，跳过空行
            List<String> oneLine = Arrays.stream(objects)
                    .map(o -> StrUtil.trim(Objects.toString(o, EMPTY)))
                    .collect(Collectors.toList());
            if (oneLine.stream().allMatch(StrUtil::isEmpty)) {
                log.info("第{}行全为空，跳过该行", currentRow);
                continue;
            }

            building = new BuildingAddReq();
            unit = new UnitAddReq();
            unit.setUnitOrder(i);
            StringBuffer errorMessages = new StringBuffer();

            // 小区编号
            villageCode = String.valueOf(objects[0]) == "null" ? "" : String.valueOf(objects[0]);
            if (StringUtils.isBlank(villageCode) || length(villageCode) > 64 ||  !CacheMap.VILLAGE_INFO_MAP.containsKey(villageCode)) {
                //添加错误的行数
                String errorMsg = appendErrorMsg(fieldList.get(0).getTitle(), villageCode, fieldList.get(0).getErrorMsg());
                errorMessages.append(errorMsg);
                isError = true;
            } else {
                building.setVillageCode(villageCode);
            }

            // 楼栋编号
            String buildingNo = String.valueOf(objects[1]) == "null" ? "" : String.valueOf(objects[1]);
            if (StringUtils.isBlank(buildingNo) || length(buildingNo) > 64) {
                //添加错误的行数
                String errorMsg = appendErrorMsg(fieldList.get(1).getTitle(), buildingNo, fieldList.get(1).getErrorMsg());
                errorMessages.append(errorMsg);
                isError = true;
            } else {
                if (!buildMap.containsKey(villageCode + buildingNo)) {
                    building.setBuildingNo(buildingNo);
                    buildMap.put(villageCode +buildingNo, building);
                    isNewBuilding = true;
                } else {
                    building = buildMap.get(villageCode + buildingNo);
                    isNewBuilding = false;
                }
            }
            //单元号
            String unitNo = String.valueOf(objects[2]) == "null" ? "" : String.valueOf(objects[2]);
            if (StringUtils.isBlank(unitNo)|| length(unitNo) > 10) {
                //添加错误的行数
                String errorMsg = appendErrorMsg(fieldList.get(2).getTitle(), unitNo, fieldList.get(2).getErrorMsg());
                errorMessages.append(errorMsg);
                isError = true;
            } else {
                String unitNokey = villageCode + "_" + buildingNo + "_" + unitNo;
                if (unitAddReqMap.containsKey(unitNokey)) { //去重判断，如果小区编码，楼栋号，单元号一样，用最后一个
                    unit = unitAddReqMap.get(unitNokey);
                } else {
                    building.getUnits().add(unit);
                    unitAddReqMap.put(unitNokey, unit);
                }
                unit.setUnitNo(unitNo);
            }
            // 楼层起始数
            String floorStartCounts = String.valueOf(objects[3]) == "null" ? "" : String.valueOf(objects[3]);
            if (StringUtils.isBlank(floorStartCounts)
                    || !RegExUtils.isNumeric(floorStartCounts)
                    || Integer.parseInt(floorStartCounts) < 1
                    || Integer.parseInt(floorStartCounts) > 150) {
                //添加错误的行数
                String errorMsg = appendErrorMsg(fieldList.get(3).getTitle(), floorStartCounts, fieldList.get(3).getErrorMsg());
                errorMessages.append(errorMsg);
                isError = true;
            } else {
                unit.setFloorStart(Integer.parseInt(floorStartCounts));
            }
            // 楼层结束数
            String floorEndCounts = String.valueOf(objects[4]) == "null" ? "" : String.valueOf(objects[4]);
            if (StringUtils.isBlank(floorEndCounts)
                    || !RegExUtils.isNumeric(floorEndCounts)
                    || Integer.parseInt(floorEndCounts) < 1
                    || Integer.parseInt(floorEndCounts) > 150) {
                //添加错误的行数
                String errorMsg = appendErrorMsg(fieldList.get(4).getTitle(), floorEndCounts, fieldList.get(4).getErrorMsg());
                errorMessages.append(errorMsg);
                isError = true;
            } else {
                unit.setFloorEnd(Integer.parseInt(floorEndCounts));
            }
            // 房号起始数
            String houseNoStart = String.valueOf(objects[5]) == "null" ? "" : String.valueOf(objects[5]);
            if (StringUtils.isBlank(houseNoStart)
                    || !RegExUtils.isNumeric(houseNoStart)
                    || Integer.parseInt(houseNoStart) < 1
                    || Integer.parseInt(houseNoStart) > 100) {
                //添加错误的行数
                String errorMsg = appendErrorMsg(fieldList.get(5).getTitle(), houseNoStart, fieldList.get(5).getErrorMsg());
                errorMessages.append(errorMsg);
                isError = true;
            } else {
                unit.setHouseNoStart(Integer.parseInt(houseNoStart));
            }
            // 每层户数
            String houseCounts = String.valueOf(objects[6]) == "null" ? "" : String.valueOf(objects[6]);
            if (StringUtils.isBlank(houseCounts)
                    || !RegExUtils.isNumeric(houseCounts)
                    || Integer.parseInt(houseCounts) < 1
                    || Integer.parseInt(houseCounts) > 100) {
                //添加错误的行数
                String errorMsg = appendErrorMsg(fieldList.get(6).getTitle(), houseCounts, fieldList.get(6).getErrorMsg());
                errorMessages.append(errorMsg);
                isError = true;
            } else {
                unit.setHouseCounts(Integer.parseInt(houseCounts));
            }

            if (isError) {
                errorCount++;
                BuildExportModel exportModel = new BuildExportModel();
                exportModel.setVillageCode(String.valueOf(objects[0]));
                exportModel.setBuildingNo(String.valueOf( objects[1]));
                exportModel.setUnitNo(String.valueOf(objects[2]));
                exportModel.setFloorStart(String.valueOf(objects[3]));
                exportModel.setFloorEnd(String.valueOf(objects[4]));
                exportModel.setHouseNoStart(String.valueOf(objects[5]));
                exportModel.setHouseCounts(String.valueOf(objects[6]));
                exportModel.setErrorMsg(errorMessages.toString());
                dataListCopy.add(exportModel);
            } else if (isNewBuilding) {
                buildList.add(building);
            }
        }


        try {
            progressTag.put(taskId, 60);
            if (CollectionUtils.isNotEmpty(buildList)) {
                for (BuildingAddReq buildingAddReq : buildList) {
                    Result result = new Result();
                    BuildingExitsReq buildingExitsReq = new BuildingExitsReq();
                    buildingExitsReq.setVillageCode(buildingAddReq.getVillageCode());
                    buildingExitsReq.setBuildingNo(buildingAddReq.getBuildingNo());
                    BuildingEntity existBuilding = buildingService.getExistBildings(buildingExitsReq);
                    if (existBuilding == null) {
                        result = buildingService.add(buildingAddReq);
                    } else {
                        BuildingEditReq buildingEditReq = new BuildingEditReq();
                        BeanUtils.copyProperties(buildingAddReq, buildingEditReq);
                        buildingEditReq.setId(existBuilding.getId());
                        result = buildingService.edit(buildingEditReq);
                    }
                    if (!result.isOk()) {
                        throw new BusinessException(result.getResultCode(), result.getResultMessage());
                    }
                }
            }
            //正常的数据需要导入进去，错误的数据返回到Excel
            if (errorCount > 0) {
                String errorFileName = exportExcelToLocal(taskId,fileName,headerTitle,dataListCopy);
                progressTag.put(taskId,100);
                return errorFileName;
            }
        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            log.error("导入楼栋信息失败,保存数据库异常！", e);
            throw new BusinessException(ExceptionCode.BUILDING_SQL_EXCEPTION_CODE, "导入楼栋信息失败,保存数据库异常！");
        }
        log.info("楼栋导入完成");
        progressTag.put(taskId, 100);
        return "";
    }

    @Override
    public int getImportDataProgress(String taskId) {
        return progressTag.get(taskId) == null ? 0 : progressTag.get(taskId);
    }
}
